/**
 * Moondance UML modeling tool
 * 
 * This program is free software; you can redistribute it and
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package ro.pub.cs.se.moondance.editpart.factory;

import org.eclipse.gef.palette.CombinedTemplateCreationEntry;
import org.eclipse.gef.palette.ConnectionCreationToolEntry;
import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteToolbar;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.requests.SimpleFactory;
import org.eclipse.jface.resource.ImageDescriptor;

import ro.pub.cs.se.moondance.MoondanceData;
import ro.pub.cs.se.moondance.MoondancePlugin;
import ro.pub.cs.se.moondance.model.ClassFunction;
import ro.pub.cs.se.moondance.model.ClassVariable;
import ro.pub.cs.se.moondance.model.Connection;
import ro.pub.cs.se.moondance.model.UMLClass;
import ro.pub.cs.se.moondance.model.UMLClassDiagram;
import ro.pub.cs.se.moondance.model.UMLCompositeState;
import ro.pub.cs.se.moondance.model.UMLEndState;
import ro.pub.cs.se.moondance.model.UMLInterface;
import ro.pub.cs.se.moondance.model.UMLPackage;
import ro.pub.cs.se.moondance.model.UMLRegion;
import ro.pub.cs.se.moondance.model.UMLStartState;
import ro.pub.cs.se.moondance.model.UMLState;
import ro.pub.cs.se.moondance.model.UMLStateDiagram;
import ro.pub.cs.se.moondance.model.UMLStateMachine;

/**
 * Utility class that can create a GEF Palette.
 * 
 * @see #createPalette()
 */
public final class EditorPaletteFactory {

	/**
	 * UML Class Diagrams Pallete
	 */

	/** Create the "UML" drawer. */
	private static PaletteContainer createUMLClassDrawer() {
		PaletteDrawer componentsDrawer = new PaletteDrawer(
				"Class Diagram components");

		/**
		 * Insert into Pallete the components
		 */
		componentsDrawer.add(new CombinedTemplateCreationEntry("Package",
				"Create new Package/Namespace", UMLPackage.class,
				new SimpleFactory(UMLPackage.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/class_types/package_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_types/package_big.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("Class",
				"Create new Class", UMLClass.class, new SimpleFactory(
						UMLClass.class), ImageDescriptor.createFromFile(
						MoondancePlugin.class,
						"icons/class_types/class_small.gif"), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/class_types/class_big.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("Interface",
				"Create new Interface", UMLInterface.class, new SimpleFactory(
						UMLInterface.class), ImageDescriptor.createFromFile(
						MoondancePlugin.class,
						"icons/class_types/interface_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_types/interface_big.gif")));

		return componentsDrawer;
	}

	private static PaletteContainer createUMLClassModifiers() {
		PaletteDrawer componentsModifiers = new PaletteDrawer(
				"Class components");

		/*
		 * The palette contains: function - can be private, protected, public or
		 * static variable - can be private, protected, public or static
		 */

		componentsModifiers.add(new CombinedTemplateCreationEntry("Function",
				"Add new Function to Class", ClassFunction.class,
				new SimpleFactory(ClassFunction.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/class_components/function_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_components/function_big.gif")));

		componentsModifiers.add(new CombinedTemplateCreationEntry("Variable",
				"Add new Variable to Class", ClassVariable.class,
				new SimpleFactory(ClassVariable.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/class_components/variable_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_components/variable_big.gif")));

		return componentsModifiers;
	}

	/** Create the "Tools" group. */
	private static PaletteContainer createUMLClassToolsGroup(PaletteRoot palette) {
		PaletteToolbar toolbar = new PaletteToolbar("Tools");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolbar.add(tool);
		palette.setDefaultEntry(tool);

		// Add a marquee tool to the group
		toolbar.add(new MarqueeToolEntry());

		/**
		 * Toolbar content: Association, Directed association, Aggregation,
		 * Composition, Inheritance, Realization
		 */

		// Association
		tool = new ConnectionCreationToolEntry("Association",
				"Create an Association between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.ASSOCIATION;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/association_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/association_big.gif"));
		toolbar.add(tool);

		// Directed association
		tool = new ConnectionCreationToolEntry(
				"Directed Association",
				"Create a Directed Association between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.DIRECTED_ASSOCIATION;
					}
				},
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/direct_association_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/direct_association_big.gif"));
		toolbar.add(tool);

		// Aggregation
		tool = new ConnectionCreationToolEntry("Aggregation",
				"Create an Aggregation between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.AGGREGATION;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/aggregation_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/aggregation_big.gif"));
		toolbar.add(tool);

		// Composition
		tool = new ConnectionCreationToolEntry("Composition",
				"Create a Composition between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.COMPOSITION;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/composition_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/composition_big.gif"));
		toolbar.add(tool);

		// Inheritance
		tool = new ConnectionCreationToolEntry("Inheritance",
				"Create an Inheritance between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.INHERITANCE;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/inheritance_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/inheritance_big.gif"));
		toolbar.add(tool);

		// Realization
		tool = new ConnectionCreationToolEntry("Realization",
				"Create an Realization between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					public Object getObjectType() {
						return Connection.REALIZATION;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/realization_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/realization_big.gif"));
		toolbar.add(tool);

		return toolbar;
	}

	/**
	 * Creates the PaletteRoot and adds all palette elements. Use this factory
	 * method to create a new palette for your graphical editor.
	 * 
	 * @return a new PaletteRoot
	 */
	public static PaletteRoot createPalette() {
		PaletteRoot palette = new PaletteRoot();

		if (MoondanceData.getCurrentDiagram() == null)
			return palette;

		if (MoondanceData.getCurrentDiagram() instanceof UMLClassDiagram) {
			palette.add(createUMLClassToolsGroup(palette));
			palette.add(createUMLClassDrawer());
			palette.add(createUMLClassModifiers());
		} else if (MoondanceData.getCurrentDiagram() instanceof UMLStateDiagram) {
			palette.add(createUMLStateToolsGroup(palette));
			palette.add(createUMLStateDrawer());
		}
		return palette;
	}

	/** Utility class. */
	public EditorPaletteFactory() {
	}

	/** Create the State drawer. */
	public static PaletteContainer createUMLStateDrawer() {
		PaletteDrawer componentsDrawer = new PaletteDrawer(
				"State Diagram components");

		/**
		 * Insert into Pallete the components
		 */
		componentsDrawer.add(new CombinedTemplateCreationEntry("Start State",
				"Create new Satrt State", UMLStartState.class,
				new SimpleFactory(UMLStartState.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/state/start_state_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/state/start_state_small.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("End State",
				"Create new End State", UMLEndState.class, new SimpleFactory(
						UMLEndState.class), ImageDescriptor.createFromFile(
						MoondancePlugin.class,
						"icons/state/end_state_small.gif"), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/state/end_state_small.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("State",
				"Create new State", UMLState.class, new SimpleFactory(
						UMLState.class), ImageDescriptor.createFromFile(
						MoondancePlugin.class, "icons/state/state_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/state/state_small.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry(
				"CompositeState", "Create new CompositeState",
				UMLCompositeState.class, new SimpleFactory(
						UMLCompositeState.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/state/composite_state_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/state/composite_state_small.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("StateMachine",
				"Create new StateMachine", UMLStateMachine.class,
				new SimpleFactory(UMLStateMachine.class), ImageDescriptor
						.createFromFile(MoondancePlugin.class,
								"icons/state/state_machine_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/state/state_machine_small.gif")));

		componentsDrawer.add(new CombinedTemplateCreationEntry("Region",
				"Create new Region", UMLRegion.class, new SimpleFactory(
						UMLRegion.class), ImageDescriptor.createFromFile(
						MoondancePlugin.class, "icons/state/region_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/state/region_small.gif")));

		return componentsDrawer;
	}

	private static PaletteContainer createUMLStateToolsGroup(PaletteRoot palette) {
		PaletteToolbar toolbar = new PaletteToolbar("Tools");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolbar.add(tool);
		palette.setDefaultEntry(tool);

		// Add a marquee tool to the group
		toolbar.add(new MarqueeToolEntry());

		/**
		 * Toolbar content: Association, Directed association, Aggregation,
		 * Composition, Inheritance, Realization
		 */

		// Association
		tool = new ConnectionCreationToolEntry("Association",
				"Create an Association between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.ASSOCIATION;
					}
				}, ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/association_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/association_big.gif"));
		toolbar.add(tool);

		// Directed association
		tool = new ConnectionCreationToolEntry(
				"Directed Association",
				"Create a Directed Association between two blocks",
				new CreationFactory() {
					public Object getNewObject() {
						return null;
					}

					// see ShapeEditPart#createEditPolicies()
					// this is abused to transmit the desired line style
					public Object getObjectType() {
						return Connection.DIRECTED_ASSOCIATION;
					}
				},
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/direct_association_small.gif"),
				ImageDescriptor.createFromFile(MoondancePlugin.class,
						"icons/class_connections/direct_association_big.gif"));
		toolbar.add(tool);

		return toolbar;
	}
}
